package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/qiuliaogit/commonutils/commonutils"
	"io"
	"net/http"
	"net/url"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"time"
)

// PostRequest 发起一个 POST 请求，上传 JSON 数据并返回 JSON 响应
func PostRequest(url string, headers map[string]string, body interface{}) (map[string]interface{}, error) {
	// 将 body 转换成 JSON 格式
	jsonData, err := json.Marshal(body)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal body: %v", err)
	}

	// 创建一个新的 POST 请求
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %v", err)
	}

	// 设置请求头
	for key, value := range headers {
		req.Header.Set(key, value)
	}
	req.Header.Set("Content-Type", "application/json")

	// 执行请求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("request failed: %v", err)
	}
	defer resp.Body.Close()

	// 读取响应 body
	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("failed to read response body: %v", err)
	}

	// 解析 JSON 响应
	var responseData map[string]interface{}
	err = json.Unmarshal(respBody, &responseData)
	if err != nil {
		return nil, fmt.Errorf("failed to unmarshal response: %v", err)
	}

	return responseData, nil
}

// GetRequest 发起一个 GET 请求，URL 上行数据是查询参数，返回 JSON 响应
func GetRequest(urlStr string, headers map[string]string, params map[string]string) (map[string]interface{}, error) {
	// 构建查询参数
	queryParams := url.Values{}
	for key, value := range params {
		queryParams.Add(key, value)
	}

	// 构造完整的 URL，包含查询参数
	finalURL := urlStr + "?" + queryParams.Encode()

	// 创建一个新的 GET 请求
	req, err := http.NewRequest("GET", finalURL, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %v", err)
	}

	// 设置请求头
	for key, value := range headers {
		req.Header.Set(key, value)
	}

	// 执行请求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("request failed: %v", err)
	}
	defer resp.Body.Close()

	// 读取响应 body
	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("failed to read response body: %v", err)
	}

	// 解析 JSON 响应
	var responseData map[string]interface{}
	err = json.Unmarshal(respBody, &responseData)
	if err != nil {
		return nil, fmt.Errorf("failed to unmarshal response: %v", err)
	}

	return responseData, nil
}

// GetRequest 发起一个 GET 请求，URL 上行数据是查询参数，返回 JSON 响应
func GetRequestFromStruct(urlStr string, headers map[string]string, params interface{}) (map[string]interface{}, error) {
	// 构建查询参数
	queryParams, err := structToQueryParams(params)
	if err != nil {
		return nil, fmt.Errorf("failed to convert struct to query params: %v", err)
	}

	// 构造完整的 URL，包含查询参数
	finalURL := urlStr + "?" + queryParams.Encode()
	fmt.Println(finalURL)

	// 创建一个新的 GET 请求
	req, err := http.NewRequest("GET", finalURL, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %v", err)
	}

	// 设置请求头
	for key, value := range headers {
		req.Header.Set(key, value)
	}

	// 执行请求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("request failed: %v", err)
	}
	defer resp.Body.Close()

	// 读取响应 body
	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("failed to read response body: %v", err)
	}

	// 解析 JSON 响应
	var responseData map[string]interface{}
	err = json.Unmarshal(respBody, &responseData)
	if err != nil {
		return nil, fmt.Errorf("failed to unmarshal response: %v", err)
	}

	return responseData, nil
}

// structToQueryParams 将结构体转换为 URL 查询参数，且按字母顺序排序
func structToQueryParams2(params interface{}) (url.Values, error) {
	// 获取传入的结构体类型和值
	val := reflect.ValueOf(params)
	if val.Kind() != reflect.Struct {
		return nil, fmt.Errorf("expected a struct, got %v", val.Kind())
	}

	// 创建一个 map 来保存查询参数
	queryParams := url.Values{}

	// 遍历结构体字段
	typ := val.Type()
	for i := 0; i < val.NumField(); i++ {
		field := typ.Field(i)
		value := val.Field(i)

		// 只处理导出字段（首字母大写的字段）
		if field.IsExported() {
			// 转换结构体字段值为字符串
			paramValue := fmt.Sprintf("%v", value.Interface())
			queryParams.Add(field.Name, paramValue)
		}
	}

	// 按字母顺序排序查询参数
	keys := make([]string, 0, len(queryParams))
	for key := range queryParams {
		keys = append(keys, key)
	}
	sort.Strings(keys)

	// 创建一个新的 url.Values 来存储排序后的参数
	sortedQueryParams := url.Values{}
	for _, key := range keys {
		// 保证参数的值按原始顺序添加
		for _, value := range queryParams[key] {
			sortedQueryParams.Add(key, value)
		}
	}

	return sortedQueryParams, nil
}

// structToQueryParams 将结构体转换为 URL 查询参数，且按字母顺序排序
func structToQueryParams(params interface{}) (url.Values, error) {
	// 获取传入的结构体类型和值
	val := reflect.ValueOf(params)
	if val.Kind() != reflect.Struct {
		return nil, fmt.Errorf("expected a struct, got %v", val.Kind())
	}

	// 创建一个 map 来保存查询参数
	queryParams := url.Values{}

	// 遍历结构体字段
	typ := val.Type()
	for i := 0; i < val.NumField(); i++ {
		field := typ.Field(i)
		value := val.Field(i)

		// 获取 json 标签值，默认使用字段名
		jsonTag := field.Tag.Get("json")
		if jsonTag == "" {
			jsonTag = field.Name
		} else {
			// 处理 json 标签时，忽略 `omitempty` 等选项
			if idx := strings.Index(jsonTag, ","); idx != -1 {
				jsonTag = jsonTag[:idx]
			}
		}

		// 只处理导出字段（首字母大写的字段）
		if field.IsExported() {
			// 转换结构体字段值为字符串
			paramValue := fmt.Sprintf("%v", value.Interface())
			queryParams.Add(jsonTag, paramValue)
		}
	}

	// 按字母顺序排序查询参数
	keys := make([]string, 0, len(queryParams))
	for key := range queryParams {
		keys = append(keys, key)
	}
	sort.Strings(keys)

	// 创建一个新的 url.Values 来存储排序后的参数
	sortedQueryParams := url.Values{}
	for _, key := range keys {
		// 保证参数的值按原始顺序添加
		for _, value := range queryParams[key] {
			sortedQueryParams.Add(key, value)
		}
	}
	return sortedQueryParams, nil
}
func StructToQueryParams3(params interface{}) (url.Values, error) {
	// 获取传入的结构体类型和值
	val := reflect.ValueOf(params)
	if val.Kind() != reflect.Struct {
		return nil, fmt.Errorf("expected a struct, got %v", val.Kind())
	}

	// 创建一个 map 来保存查询参数
	queryParams := url.Values{}

	// 遍历结构体字段
	typ := val.Type()
	for i := 0; i < val.NumField(); i++ {
		field := typ.Field(i)
		value := val.Field(i)

		// 检查字段是否有 json tag
		jsonTag := field.Tag.Get("json")
		if jsonTag == "" {
			continue // 如果没有 json tag，跳过该字段
		}

		// 处理 tag 中的字段名称（支持忽略 `omitempty`）
		paramName := jsonTag
		// 只有非空的字段才添加到查询参数
		if value.IsValid() && !value.IsZero() {
			paramValue := fmt.Sprintf("%v", value.Interface())
			queryParams.Add(paramName, paramValue)
		}
	}

	return queryParams, nil
}

// structToQueryParams 将带有json标记的结构体转换为url.Values
// AllocOmitempty=true时处理omitempty标记，否则忽略
func StructToQueryParams5(input interface{}, AllocOmitempty bool) (url.Values, error) {
	values := url.Values{}
	v := reflect.ValueOf(input)

	// 处理指针类型
	if v.Kind() == reflect.Ptr {
		if v.IsNil() {
			return values, nil
		}
		v = v.Elem()
	}

	// 仅处理结构体
	if v.Kind() != reflect.Struct {
		return nil, fmt.Errorf("input must be a struct")
	}

	t := v.Type()
	for i := 0; i < v.NumField(); i++ {
		fieldValue := v.Field(i)
		fieldType := t.Field(i)

		// 解析json标签
		jsonTag := fieldType.Tag.Get("json")
		jsonName, omitempty := parseJSONTag(jsonTag, fieldType.Name)

		// 跳过"-"标记字段
		if jsonName == "-" {
			continue
		}

		// 处理omitempty逻辑
		if AllocOmitempty && omitempty && isEmptyValue(fieldValue) {
			continue
		}

		// 值转换
		strValue, err := valueToString(fieldValue)
		if err != nil {
			return nil, fmt.Errorf("字段[%s]转换失败: %v", jsonName, err)
		}

		if strValue != "" {
			values.Add(jsonName, strValue)
		}
	}

	return values, nil
}

// parseJSONTag 解析json标签，返回字段名和omitempty标记
func parseJSONTag(tag, fieldName string) (string, bool) {
	if tag == "" {
		return strings.ToLower(fieldName), false
	}

	parts := strings.Split(tag, ",")
	name := parts[0]

	switch {
	case name == "-":
		return "-", false
	case name == "":
		name = strings.ToLower(fieldName)
	}

	omitempty := false
	for _, part := range parts[1:] {
		if strings.TrimSpace(part) == "omitempty" {
			omitempty = true
		}
	}

	return name, omitempty
}

// isEmptyValue 判断是否零值（支持嵌套指针）
func isEmptyValue(v reflect.Value) bool {
	// 解除指针嵌套
	for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
		if v.IsNil() {
			return true
		}
		v = v.Elem()
	}

	switch v.Kind() {
	case reflect.String:
		return v.Len() == 0
	case reflect.Array, reflect.Slice, reflect.Map:
		return v.Len() == 0
	case reflect.Bool:
		return !v.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return v.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return v.Float() == 0
	case reflect.Struct:
		// 特殊处理time.Time
		if t, ok := v.Interface().(time.Time); ok {
			return t.IsZero()
		}
		return false
	default:
		return false
	}
}

// valueToString 值类型转换（支持常见类型和嵌套指针）
func valueToString(v reflect.Value) (string, error) {
	// 处理指针嵌套
	for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
		if v.IsNil() {
			return "", nil
		}
		v = v.Elem()
	}

	switch v.Kind() {
	case reflect.String:
		return v.String(), nil
	case reflect.Bool:
		return strconv.FormatBool(v.Bool()), nil
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return strconv.FormatInt(v.Int(), 10), nil
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return strconv.FormatUint(v.Uint(), 10), nil
	case reflect.Float32, reflect.Float64:
		return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil
	case reflect.Struct:
		if t, ok := v.Interface().(time.Time); ok {
			return t.Format(time.RFC3339), nil
		}
		return commonutils.Struct2Json(v.Interface())
	case reflect.Slice, reflect.Array:
		var parts []string
		for i := 0; i < v.Len(); i++ {
			part, err := valueToString(v.Index(i))
			if err != nil {
				return "", err
			}
			parts = append(parts, part)
		}
		return strings.Join(parts, ","), nil
	default:
		return commonutils.Struct2Json(v.Interface())
	}
}

func main() {
	//host := "https://admingo.gamelabs.vip"
	//path_login := "/tob/v1/login_pwd"
	type loginRequest struct {
		Account string `json:"xaccount"`
		Pwd     string `json:"apwd"`
		Value   int    `json:"value2,omitempty"`
		Value1  int    `json:"value1,omitempty"`
	}

	req := loginRequest{
		Account: "admin",
		Pwd:     "Abcd@1235",
		Value:   199,
		Value1:  0,
	}

	//rsp, err := PostRequest(host+path_login, nil, req)
	//fmt.Printf("rsp: %v, err: %v\n", rsp, err)

	type GetRequest struct {
		Aid    int           `json:"aid"`
		UUID   string        `json:"uuid"`
		Spider int           `json:"spider"`
		WebId  int64         `json:"web_id"`
		KK     *loginRequest `json:"kk,omitempty"`
	}

	getReq := GetRequest{
		Aid:    2608,
		UUID:   "7419192284367259177",
		Spider: 0,
		WebId:  7419192284367259177,
		KK:     &req,
	}

	q1, err := structToQueryParams2(getReq)
	if err == nil {
		fmt.Println(q1.Encode())
	}
	q2, err := structToQueryParams(getReq)
	if err == nil {
		fmt.Println(q2.Encode())
	}
	q3, err := commonutils.Struct2Json(getReq)
	if err == nil {
		fmt.Println(q3)
	}
	q4, err := StructToQueryParams3(getReq)
	if err == nil {
		fmt.Println(q4.Encode())
	}
	q5, err := StructToQueryParams5(nil, true)
	if err == nil {
		fmt.Println(q5.Encode(), true)
	} else {
		fmt.Println("has error:" + err.Error())
	}
	q6, err := StructToQueryParams5(getReq, false)
	if err == nil {
		fmt.Println(q6.Encode(), false)
	}
	fmt.Println("-------------")
	q1, err = structToQueryParams2(req)
	if err == nil {
		fmt.Println(q1.Encode())
	}
	q2, err = structToQueryParams(req)
	if err == nil {
		fmt.Println(q2.Encode())
	}
	q3, err = commonutils.Struct2Json(req)
	if err == nil {
		fmt.Println(q3)
	}
	q4, err = StructToQueryParams3(req)
	if err == nil {
		fmt.Println(q4.Encode())
	}
	q5, err = StructToQueryParams5(req, true)
	if err == nil {
		fmt.Println(q5.Encode(), true)
	}
	q6, err = StructToQueryParams5(req, false)
	if err == nil {
		fmt.Println(q6.Encode(), false)
	}
	//
	//nnn, err := GetRequestFromStruct("https://api.juejin.cn/user_api/v1/user/profile_id", nil, getReq)
	//fmt.Printf("nnn: %v, err: %v\n", nnn, err)
}
